#include <sys/types.h>
#include <sys/socket.h>
#include <linux/in.h>
#include <linux/if_ether.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "ipt_ipmac.h"
#define NIPQUAD(addr) \
        ((unsigned char *)&addr)[0], \
        ((unsigned char *)&addr)[1], \
        ((unsigned char *)&addr)[2], \
        ((unsigned char *)&addr)[3]
#define NMACQUAD(mac) mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]

void parseip(struct in_addr *ip, char *ipstr)
{
	int i;
	char *addr, *q;
	addr = (char *)&ip->s_addr;
	q = strtok(ipstr, ".");
	if (!q) {
		printf("error ip\n");
		exit(1);
	}
	addr[0] = (char)atoi(q);
	for ( i = 1; i < 4; i++) {
		q = strtok(NULL, ".");
		if (!q) {
			printf("error ip\n");
			exit(1);
		}	
		addr[i] = (char)atoi(q);
	}
}

void parsemac(unsigned char *mac, char *macstr)
{
	int i;
	char *q;
	q = strtok(macstr, ":");
	if (!q) {
		printf("error mac\n");
		exit(1);
	}
	mac[0] = strtol(q,NULL,16);
	for ( i = 1; i < ETH_ALEN; i++) {
		q = strtok(NULL, ":");
		if (!q) {
			printf("error mac\n");
			exit(1);
		}	
		mac[i] = strtol(q,NULL,16);
	}
}

append(char *ipstr, char *macstr)
{
	int sockfd;
	struct IPMAC ipmac;
	parseip(&ipmac.ip, ipstr);
	parsemac(ipmac.mac, macstr);
#ifdef DEBUG
	printf("%u.%u.%u.%u %x:%x:%x:%x:%x:%x\n",
		NIPQUAD(ipmac.ip.s_addr),
		NMACQUAD(ipmac.mac));
#endif
	sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
	if (setsockopt(sockfd, IPPROTO_IP, IPT_ADD_CTL, &ipmac, sizeof(ipmac))) {
		printf("setsockopt error\n");
		exit(1);
	}
}


del(char *ipstr)
{
	int sockfd;
	struct IPMAC ipmac;
	parseip(&ipmac.ip,ipstr);
	sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
	if (setsockopt(sockfd, IPPROTO_IP, IPT_DEL_CTL, &ipmac, sizeof(ipmac))) {
		printf("setsockopt error\n");
		exit(1);
	}	
}

flush()
{
	int sockfd;
	sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
	if (setsockopt(sockfd, IPPROTO_IP, IPT_FLUSH_CTL, NULL, 0)) {
		printf("setsockopt error\n");
		exit(1);
	}	
}

list()
{
	int sockfd, num, len, i;
	struct IPMAC *data;
	sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
	len = sizeof(int);
	if (getsockopt(sockfd, IPPROTO_IP, IPT_GET_NUM_CTL, &num, &len)) {
		printf("getsockopt error\n");
		exit(1);
	}	
	printf("Rule num = %d\n", num);
	if (num) {
		len = num * sizeof(struct IPMAC);
		data = (struct IPMAC *) malloc(len);
		if (getsockopt(sockfd, IPPROTO_IP, IPT_GET_RULE_CTL, data, &len))
			printf("getsockopt error\n");
		else {
			len /= sizeof(struct IPMAC);
			for ( i = 0; i < len; i++)
				printf("%u.%u.%u.%u %x:%x:%x:%x:%x:%x\n",
					NIPQUAD(data[i].ip.s_addr),
					NMACQUAD(data[i].mac));
		}
	}	
}	

void help(void)
{
	printf("Usage:\tIPMACcfg A ip mac\n");
	printf("\tIPMACcfg D ip\n");
	printf("\tIPMACcfg F\n");
	printf("\tIPMACcfg L\n");
	printf("\tIPMACcfg h\n\n");
	printf("Commands:\n");
	printf("\tA ip mac\t\tAppend ip-mac pair to list\n");
	printf("\tD ip\t\tDelete ip-mac pair from list\n");
	printf("\tF\t\tDelete all in list\n");
	printf("\tL\t\tList all in list\n");
	printf("\th\t\tPrint this help information\n");
}	

main(int argc, char *argv[])
{
	int c, sockfd, command = 0;
	if(argc>=2&&strlen(argv[1])==1) {
		switch(argv[1][0]) {
		case 'A':
			if(argc!=4) break;
			command = 1;
			append(argv[2],argv[3]);
			break;
		case 'D':
			if(argc!=3) break;
			command = 1;
			del(argv[2]);
			break;
		case 'F':
			if(argc!=2) break;
			command = 1;
			flush();
			break;
		case 'L':
			if(argc!=2) break;
			command = 1;
			list();
			break;
		case 'h':
			if(argc!=2) break;
			command = 1;
			help();
			break;
		}
	}	
	if (!command)
		printf("Try `%s h' for more information.\n", argv[0]);
}
